﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.ObjectModel;
using BrainTechLLC.ImageOperators;
using BrainTechLLC.WPF;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using BrainTechLLC;
using CPPClassLibrary;
using DirectoryViewModels;
using ImageAppDataModels;
using ImageAppViewModels;
using System.IO;
using System.Collections.Generic;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;
using System.Drawing;
using System.Windows.Media;
using System.Reflection;
using BinaryNorthwest;
using BrainTechLLC.FilterExtensions;
using System.Windows.Controls;
using System.ServiceModel;
using System.Threading;
using System.ServiceModel.Description;

namespace WpfImageDuplicates
{
    public partial class Window1
    {
        public PluginDefinitionLoaded<IFullViewerWindowHandler> _FullViewerHandler;
        public PluginDefinitionLoaded<IFolderExplorerWindowHandler> _FolderHandler;
        public PluginDefinitionLoaded<ICompareWindowHandler> _CompareHandler;
        public PluginDefinitionLoaded<ISettingsWindowHandler> _SettingsHandler;
        public PluginDefinitionLoaded<IShowMultipleImagesWindowHandler> _ShowMultipleHandler;
        public PluginDefinitionLoaded<ICompareMultipleWindowHandler> _CompareMultiple;
        public PluginDefinitionLoaded<IEventInfoWindowHandler> _EventWindowHandler;
        public PluginDefinitionLoaded<IStatsWindowHandler> _StatsHandler;

        private void CheckRegisterMenuOption(PluginDefinitionLoadedBase definition, Type[] types, bool menuPlugins, Assembly a, FileInfo file)
        {
            for (int n = 0; n < types.Length; n++)
            {
                var type = types[n];
                if (menuPlugins && type.GetInterface("IRegisterMenuOption") != null)
                {
                    if (a.ReflectionOnly)
                    {
                        a = Assembly.LoadFile(file.FullName);
                    }
                    type = a.GetType(type.FullName);
                    IRegisterMenuOption registerOption = type.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IRegisterMenuOption;
                    var menuItemsToInsert = registerOption.GetSharedMenuItems(definition);

                    foreach (var menuItemToInsert in menuItemsToInsert)
                    {
                        MenuItem found = null;
                        foreach (var item in this.mainMenu.Items)
                        {
                            if (item.GetType() != typeof(MenuItem))
                            {
                                continue;
                            }
                            MenuItem mi = item as MenuItem;
                            string miName = mi.Header.ToString().Replace("_", "");
                            if (miName.Equals(menuItemToInsert.TopLevelMenu, StringComparison.OrdinalIgnoreCase))
                            {
                                found = mi;
                                break;
                            }
                        }

                        if (found == null)
                        {
                            registerOption.ErrorReported("Top level menu item " + menuItemToInsert.TopLevelMenu + " not found!");
                        }
                        else
                        {
                            found.Items.Add(menuItemToInsert.MenuItem);
                        }
                    }
                }
            }
        }

        private void ScanPlugins(List<string> interfaceTypesToLoad, bool includeAll)
        {
            DirectoryInfo di = new DirectoryInfo(FilePaths._pluginsDir);
            if (di.Exists)
            {
                FileInfo[] files1 = di.GetFiles("*.plugin.dll", SearchOption.TopDirectoryOnly);
                FileInfo[] files2 = di.GetFiles("*.plugin.exe", SearchOption.TopDirectoryOnly);

                List<FileInfo> fileList = new List<FileInfo>();
                fileList.AddRange(files1);
                fileList.AddRange(files2);

                bool menuPlugins = includeAll || interfaceTypesToLoad.Contains("IRegisterMenuOption");
                bool fullViewerPlugins = includeAll || interfaceTypesToLoad.Contains("IFullViewerWindowHandler");
                bool folderPlugins = includeAll || interfaceTypesToLoad.Contains("IFolderExplorerWindowHandler");
                bool dupePlugins = includeAll || interfaceTypesToLoad.Contains("ICompareWindowHandler");
                bool showMultiplePlugins = includeAll || interfaceTypesToLoad.Contains("IShowMultipleImagesWindowHandler");
                bool compareMultPlugins = includeAll || interfaceTypesToLoad.Contains("ICompareMultipleWindowHandler");
                bool showSettingsPlugins = includeAll || interfaceTypesToLoad.Contains("ISettingsWindowHandler");
                bool showStatsPlugins = includeAll || interfaceTypesToLoad.Contains("IStatsWindowHandler");
                bool showEventHandlerPlugins = includeAll || interfaceTypesToLoad.Contains("IEventInfoWindowHandler");

                AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);

                foreach (var file in fileList)
                {
                    Assembly a;
                    try
                    {
                        a = Assembly.ReflectionOnlyLoadFrom(file.FullName);
                        Console.WriteLine(string.Format("Loaded assembly {0} for reflection", file.FullName));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(string.Format("Error trying to load types from assembly {0}: {1}", file.FullName, ex.ToString()));
                        continue;
                    }
                    try
                    {
                        Type[] types = new Type[0];
                        try
                        {
                            types = a.GetTypes();
                        }
                        catch (Exception ex2)
                        {
                            Console.WriteLine(string.Format("Error trying to load types from assembly {0}: {1}", a.FullName, ex2.ToString()));
                            continue;
                        }

                        for (int n = 0; n < types.Length; n++)
                        {
                            var type = types[n];

                            if (fullViewerPlugins && type.GetInterface("IFullViewerWindowHandler") != null)
                            {
                                _FullViewerHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_FullViewerHandler, types, menuPlugins, a, file);
                            }
                            if (folderPlugins && type.GetInterface("IFolderExplorerWindowHandler") != null)
                            {
                                _FolderHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_FolderHandler, types, menuPlugins, a, file);
                            }
                            if (dupePlugins && type.GetInterface("ICompareWindowHandler") != null)
                            {
                                _CompareHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_CompareHandler, types, menuPlugins, a, file);
                            }
                            if (showMultiplePlugins && type.GetInterface("IShowMultipleImagesWindowHandler") != null)
                            {
                                _ShowMultipleHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_ShowMultipleHandler, types, menuPlugins, a, file);
                            }
                            if (compareMultPlugins && type.GetInterface("ICompareMultipleWindowHandler") != null)
                            {
                                _CompareMultiple.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_CompareMultiple, types, menuPlugins, a, file);
                            }
                            if (showSettingsPlugins && type.GetInterface("ISettingsWindowHandler") != null)
                            {
                                _SettingsHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_SettingsHandler, types, menuPlugins, a, file);
                            }
                            if (showStatsPlugins && type.GetInterface("IStatsWindowHandler") != null)
                            {
                                _StatsHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_StatsHandler, types, menuPlugins, a, file);
                            }
                            if (showEventHandlerPlugins && type.GetInterface("IEventInfoWindowHandler") != null)
                            {
                                _EventWindowHandler.Handlers.Add(new AssemblyAndType(file.FullName, type.FullName));
                                CheckRegisterMenuOption(_EventWindowHandler, types, menuPlugins, a, file);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
            }
        }

        Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
        {
            return Assembly.ReflectionOnlyLoad(args.Name);
        }

        private void InitializePluginDefinitions()
        {
            _EventWindowHandler = new PluginDefinitionLoaded<IEventInfoWindowHandler>(this);
            _FolderHandler = new PluginDefinitionLoaded<IFolderExplorerWindowHandler>(this);
            _FolderHandler.HandlerSet += new EventHandler<ObjectEventArgs<IFolderExplorerWindowHandler>>(_FolderHandler_HandlerSet);
            _FullViewerHandler = new PluginDefinitionLoaded<IFullViewerWindowHandler>(this);
            _FullViewerHandler.HandlerSet += new EventHandler<ObjectEventArgs<IFullViewerWindowHandler>>(_FullViewerHandler_HandlerSet);
            _CompareHandler = new PluginDefinitionLoaded<ICompareWindowHandler>(this);
            _SettingsHandler = new PluginDefinitionLoaded<ISettingsWindowHandler>(this);
            _SettingsHandler.HandlerSet += new EventHandler<ObjectEventArgs<ISettingsWindowHandler>>(_SettingsHandler_HandlerSet);
            _ShowMultipleHandler = new PluginDefinitionLoaded<IShowMultipleImagesWindowHandler>(this);
            _CompareMultiple = new PluginDefinitionLoaded<ICompareMultipleWindowHandler>(this);
            _StatsHandler = new PluginDefinitionLoaded<IStatsWindowHandler>(this);
        }

        void _FullViewerHandler_HandlerSet(object sender, ObjectEventArgs<IFullViewerWindowHandler> e)
        {
            IFullViewerWindowHandler handler = e.obj;
            handler.RequestDelete += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(FullViewerHandler_RequestDelete);
            handler.RequestResize += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(FullViewerHandler_RequestResize);
            handler.RequestResizeDelete += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(FullViewerHandler_RequestResizeDelete);
            handler.RequestRotate += new EventHandler<ObjectEventArgsNonRef<RotationParams, bool>>(FullViewerHandler_RequestRotate);
        }

        void _SettingsHandler_HandlerSet(object sender, ObjectEventArgs<ISettingsWindowHandler> e)
        {
            e.obj.SettingsWatcher = SettingsWatcher;
        }

        void _FolderHandler_HandlerSet(object sender, ObjectEventArgs<IFolderExplorerWindowHandler> e)
        {
            // HEREHERE
            e.obj.DirectoriesToExamineViewModel = Window1.MainWindow.CurrentDirectoriesToExamine; // CollectionView.FileImageCollectionViewModel.DirectoriesToExamine;
            e.obj.Closed += new EventHandler(obj_Closed);
            e.obj.DropData += new EventHandler<ObjectEventArgs<object, ItemsControl, UIElement>>(obj_DropData);
            e.obj.SelectFoldersStart += new EventHandler(obj_SelectFoldersStart);
            e.obj.SelectFoldersEnd += new EventHandler(obj_SelectFoldersEnd);
            e.obj.AlwaysOnTop = Settings.Values.FolderExplorerTopmost;
        }

        void obj_SelectFoldersEnd(object sender, EventArgs e)
        {
            FinishedAddingFolders();
        }

        private void FinishedAddingFolders()
        {
            _suspendDirsViewModelCollectionChanged = false;
            Dispatcher.BeginInvoke(() => RefreshDirsViewModel());
        }

        void obj_SelectFoldersStart(object sender, EventArgs e)
        {
            BeginAddingFolders();
        }

        private void BeginAddingFolders()
        {
            _suspendDirsViewModelCollectionChanged = true;
        }

        void obj_DropData(object sender, ObjectEventArgs<object, ItemsControl, UIElement> e)
        {
            Commands.DropFromListBoxToTreeViewCommand.Execute(e.obj1, e.obj2, e.obj3);
        }

        void obj_Closed(object sender, EventArgs e)
        {
            SettingsWatcher.SettingsViewModelDynamic.FolderExplorerTopmost = _FolderHandler.Handler.AlwaysOnTop;
            SettingsWatcher.SettingsViewModelDynamic.FolderExplorerVisible = false;
        }
    }
}
